package com.heima.wemedia.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.heima.article.client.ArticleFeign;
import com.heima.common.aliyun.GreenImageUploadScan;
import com.heima.common.aliyun.GreenTextScan;
import com.heima.common.delayTask.RedisDelayedQueueUtil;
import com.heima.common.enums.AppHttpCodeEnum;
import com.heima.common.exception.LeadException;
import com.heima.common.util.BeanHelper;
import com.heima.common.util.SensitiveWordUtil;
import com.heima.file.service.MinioService;
import com.heima.model.article.dtos.ArticleDto;
import com.heima.wemedia.entity.WmNews;
import com.heima.wemedia.entity.WmSensitive;
import com.heima.wemedia.service.WmNewsAuditService;
import com.heima.wemedia.service.WmNewsService;
import com.heima.wemedia.service.WmSensitiveService;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.checkerframework.checker.units.qual.A;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
@Service
public class WmNewsAuditServiceImpl implements WmNewsAuditService {
    @Autowired
    private WmNewsService wmNewsService;

    @Autowired
    private GreenImageUploadScan imageUploadScan;

    @Autowired
    private GreenTextScan textScan;

    @Autowired
    private MinioService minioService;

    @Autowired
    private ArticleFeign articleFeign;

    @Autowired
    private WmSensitiveService wmSensitiveService;

    @Autowired
    private RedisDelayedQueueUtil redisDelayedQueueUtil;

//    @Autowired
//    private WmChannelMapper wmChannelMapper;


    /**
     * 自媒体文章审核
     *
     * @param wmNewsId 自媒体文章id
     */
    @Override
    @Async
    public void auditWmNews(Integer wmNewsId) {
        //1. 查询自媒体文章
        WmNews wmNews = wmNewsService.getById(wmNewsId);
        if (wmNews == null) {
            throw new LeadException(AppHttpCodeEnum.DATA_NOT_EXIST);
        }
        //2. 只处理待处理的
        if (wmNews.getStatus().intValue() != 1) {
            log.info("当前文章不是待审核状态！");
            return;
        }
        //3. 从内容中提取纯文本内容和图片
        Map<String, Object> map = handleTextAndImages(wmNews);
        //4. 获取所有文本内容
        String text = map.get("content").toString();
        //5. 获取所有图片地址
        Set<String> urls = (Set<String>) map.get("images");
        //  敏感词审核
        boolean b = handleSensitiveScan(text, wmNewsId);
        if (!b) {
            log.error("敏感词审核不通过，wmNewsId={}", wmNewsId);
            return;
        }
        //6. 审核所有的文本内容  阿里云接口
        boolean isTextPass = handlerAliyunText(wmNewsId, text);
        if (!isTextPass) {
            log.info("阿里云文本检测不通过，wmNewsId={}", wmNewsId);
            return;
        }
        //7. 审核图片，调用阿里云接口
        boolean isImagePass = handlerImageScan(urls, wmNewsId);
        if (!isImagePass) {
            log.info("阿里云图片检测不通过，wmNewsId={}", wmNewsId);
            return;
        }
        //8. 如果未到发布时间修改审核状态为8 （审核通过待发布）
        if (wmNews.getPublishTime() != null && wmNews.getPublishTime().getTime() > System.currentTimeMillis()) {
            // 修改文章状态
            updateWmNewsStatus(wmNewsId, 8, null, null);
            Date publishTime = wmNews.getPublishTime();
            log.info("没有到发布时间，放入延时任务，wmnewsId={}，publishTime={}",wmNewsId,publishTime);
            long delay = publishTime.getTime()- System.currentTimeMillis();
            log.info("wmNewsId={},延时时间 delay毫秒={}",wmNewsId,delay);
            redisDelayedQueueUtil.addQueue(wmNewsId,delay, TimeUnit.MILLISECONDS,"wm.news.pub");
            return;
        }
        //9. 审核成功，发布文章，保存APP端相关的文章数据
        saveArticle(wmNews);
    }
    /**
     * 发布文章
     * @param wmNewsId
     */
    @Override
    public void pubWmNews(Integer wmNewsId) {
        log.info("延迟任务，发布文章，wmNewsId={}",wmNewsId);
        WmNews wmNews = wmNewsService.getById(wmNewsId);
        if (wmNews == null) {
            log.error("自媒体文章不存在，wmNewsId={}",wmNewsId);
            throw new LeadException(AppHttpCodeEnum.DATA_NOT_EXIST);
        }
        if(wmNews.getStatus() != 4 && wmNews.getStatus() !=8){
            log.error("自媒体文章不是待发布状态，wmNewsId={}",wmNewsId);
            throw new LeadException(AppHttpCodeEnum.NO_OPERATOR_AUTH);
        }
        saveArticle(wmNews);
    }

    //自管理的敏感词审核
    private boolean handleSensitiveScan(String content, Integer wmNewsId) {
        //1. 获取所有的敏感词
        List<WmSensitive> wmSensitives = wmSensitiveService.list();
        List<String> senstiveList = wmSensitives.stream().map(WmSensitive::getSensitives).collect(Collectors.toList());
        //2. 查看文章中是否包含敏感词
        Map<String, Integer> map = SensitiveWordUtil.matchWords(senstiveList, content);
        if (!CollectionUtils.isEmpty(map)) {
            updateWmNewsStatus(wmNewsId, 2, "当前文章中存在违规内容" + map, null);
            return false;
        }
        return true;
    }

    //保存APP端相关的文章数据
    @GlobalTransactional(rollbackFor = Exception.class)
    private Long saveArticle(WmNews wmNews) {
        //1. 属性拷贝
        ArticleDto dto = BeanHelper.copyProperties(wmNews, ArticleDto.class);
        //2. 文章布局
        dto.setLayout(wmNews.getType());
        //   频道

        //3. 自媒体用户id
        dto.setWmUserId(wmNews.getWmUserId());
        dto.setWmNewsId(wmNews.getId());
        dto.setContent(wmNews.getContent());
        try {
            Long articleId = articleFeign.saveArticle(dto);
            // 回写artice_id
            updateWmNewsStatus(wmNews.getId(), 9, "发布成功", articleId);
            return articleId;
        } catch (Exception e) {
            log.error("远程调用article服务创建文章失败！");
            e.printStackTrace();
            throw new LeadException(AppHttpCodeEnum.SERVER_ERROR);
        }

    }

    //阿里云审核图片内容
    private boolean handlerImageScan(Set<String> images, Integer wmNewsId) {
        if (CollectionUtils.isEmpty(images)) {
            return true;
        }
        //1. 下载图片  minIo
        List<byte[]> imageList = new ArrayList<>();
        for (String image : images) {
            byte[] bytes = minioService.downLoadFile(image);
            imageList.add(bytes);
        }
        if (CollectionUtils.isEmpty(imageList)) {
            throw new LeadException(AppHttpCodeEnum.SERVER_ERROR);
        }
        //2. 审核图片
        try {
            Map<String, String> map = imageUploadScan.imageScan(imageList);
            if (CollectionUtils.isEmpty(map)) {
                log.error("图片返回的map集合为空");
                throw new LeadException(AppHttpCodeEnum.SERVER_ERROR);
            }
            String suggestion = map.get("suggestion");
            if ("pass".equals(suggestion)) {
                log.info("阿里云审核图片通过");
                return true;
            } else if ("review".equals(suggestion)) {
                log.info("阿里云审核图片结果不确定，转人工审核");
                // 修改状态 3
                updateWmNewsStatus(wmNewsId, 3, map.get("label"), null);
                return false;
            } else {
                log.info("阿里云审核图片结果不通过");
                // 修改状态 2
                updateWmNewsStatus(wmNewsId, 2, map.get("label"), null);
                return false;
            }
        } catch (Exception e) {
            log.error("调用阿里云接口失败！");
            e.printStackTrace();
            throw new LeadException(AppHttpCodeEnum.SERVER_ERROR);
        }
    }

    //阿里审核文本内容
    private boolean handlerAliyunText(Integer wmNewsId, String text) {
        try {
            Map<String, String> map = textScan.greenTextScan(text);
            if (CollectionUtils.isEmpty(map)) {
                log.error("文本审核接口返回的map为空");
                throw new LeadException(AppHttpCodeEnum.SERVER_ERROR);
            }
            String suggestion = map.get("suggestion");
            if (StringUtils.isBlank(suggestion)) {
                log.error("文本审核接口返回的suggestion为空");
                throw new LeadException(AppHttpCodeEnum.SERVER_ERROR);
            }
            if ("pass".equals(suggestion)) {
                log.info("阿里云文本审核通过");
                return true;
            } else if ("review".equals(suggestion)) {
                log.info("阿里云文本审核不确定，需进一步人工审核");
                //调用方法修改状态为3
                updateWmNewsStatus(wmNewsId, 3, map.get("reason"), null);
                return false;
            } else {
                //调用方法修改状态为2
                updateWmNewsStatus(wmNewsId, 2, map.get("reason"), null);
                return false;
            }
        } catch (Exception e) {
            log.error("调用阿里云审核文本失败");
            e.printStackTrace();
            throw new LeadException(AppHttpCodeEnum.SERVER_ERROR);
        }
    }

    //修改自媒体文章状态
    private void updateWmNewsStatus(Integer wmNewsId, int i, String reason, Long articleId) {
        WmNews wmNews = new WmNews();
        wmNews.setId(wmNewsId);
        wmNews.setStatus(i);
        if (StringUtils.isNotBlank(reason)) {
            wmNews.setReason(reason);
        }
        if (articleId != null) {
            wmNews.setArticleId(articleId);
        }
        wmNewsService.updateById(wmNews);
    }

    //从内容中提取纯文本内容和图片
    private Map<String, Object> handleTextAndImages(WmNews wmNews) {
        //1. 存储纯文本内容
        StringBuilder stringBuilder = new StringBuilder();
        HashSet<String> images = new HashSet<>();
        //2. 从自媒体文章的内容中提取文本和图片
        if (StringUtils.isNotBlank(wmNews.getContent())) {
            List<Map> maps = JSONArray.parseArray(wmNews.getContent(), Map.class);
            for (Map map : maps) {
                if (map.get("type").equals("text")) {
                    stringBuilder.append(map.get("value"));
                }
                if (map.get("type").equals("image")) {
                    images.add((String) map.get("value"));
                }
            }
        }
        //3. 提取文章的封面图片
        if (StringUtils.isNotBlank(wmNews.getImages())) {
            String[] split = wmNews.getImages().split(",");
            images.addAll(Arrays.asList(split));
        }
        //4. 封装返回数据
        Map<String, Object> resultMap = new HashMap<>();
        resultMap.put("content", stringBuilder.toString());
        resultMap.put("images", images);
        return resultMap;
    }
}
